//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++

THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name: 

        usbotg_ulpi.cpp

Abstract:

        Littleton USB OTG Driver.


--*/

//#define ULPI_DEBUG 
#ifdef ULPI_DEBUG
#define DBG   RETAILMSG
#else
#define DBG   DEBUGMSG
#endif

#include <windows.h>
#include <ceddk.h>
#include <ddkreg.h>
#include <nkintr.h> // needed for SYSINTR_NOP

//#include <monanhans.h>
#include <xllp_gpio.h>
#include <xllp_mfp.h>
#include <xllp_pm.h>
#include "GPX_XLLP.h"
#include <Littleton.h>
#include <xllp_mfp_plat.h>
#include "monahans.h"
#include "monahans_base_regs.h"

#include "xllp_udc.h"
#include <usbotg.hpp>

#include <Winbase.h>

#include "UsbOtg.h"

#include "args.h"
#include "ioctl_cfg.h"
#include "xllp_pm_micco.h"

#include "ipm_api.h"

#include "ULPI.h"
#include "xllp_u2d.h"

#include "ist.hpp"
#include <Windev.h>
//#include "micco.h"
#include "xllp_ost.h"
#include "UsbIoctrl.h"
#include "xllp_gpio_plat.h"
#include "clkmgr.h"
#ifdef DEBUG
#ifdef ZONE_ERROR
#undef ZONE_ERROR
#endif
#define ZONE_ERROR (1<<0)
#ifdef ZONE_INIT
#undef ZONE_INIT
#endif
#define ZONE_INIT  (1<<2)
#endif
 //GPIO 33(data 3) is mapped to interrupt pin when PHY in low power mode
#define GPIO33 33

static XLLP_UINT32_T g_U2DMFPList[] =
{     

    XLLP_MFP_U2D_ULPI_D0_OFFSET,        

    XLLP_MFP_U2D_ULPI_D1_OFFSET,    

    XLLP_MFP_U2D_ULPI_D2_OFFSET,    

    XLLP_MFP_U2D_ULPI_D3_OFFSET,    

    XLLP_MFP_U2D_ULPI_D4_OFFSET,    

    XLLP_MFP_U2D_ULPI_D5_OFFSET,    

    XLLP_MFP_U2D_ULPI_D6_OFFSET,    

    XLLP_MFP_U2D_ULPI_D7_OFFSET,
    
    XLLP_MFP_U2D_ULPI_CLK_OFFSET, 

    XLLP_MFP_PIN_ULPI_STP_OFFSET,
    
    XLLP_MFP_PIN_ULPI_NXT_OFFSET,
    
    XLLP_MFP_PIN_ULPI_DIR_OFFSET,

    XLLP_MFP_PIN_EOLIST_MARKER
};


static XLLP_MFP_ALT_FN_T g_U2DMFPDeviceAF[] = 
{

    XLLP_MFP_U2D_ULPI_D0_AF,
    
    XLLP_MFP_U2D_ULPI_D1_AF,

    XLLP_MFP_U2D_ULPI_D2_AF,

    XLLP_MFP_U2D_ULPI_D3_AF,

    XLLP_MFP_U2D_ULPI_D4_AF,

    XLLP_MFP_U2D_ULPI_D5_AF,
    
    XLLP_MFP_U2D_ULPI_D6_AF,

    XLLP_MFP_U2D_ULPI_D7_AF,

    XLLP_MFP_U2D_ULPI_CLK_AF,
    
    XLLP_MFP_ALT_FN_0,
    
    XLLP_MFP_ALT_FN_0,

    XLLP_MFP_ALT_FN_0,


};



static XLLP_MFP_ALT_FN_T g_U2DMFPHostAF[] = 
{

    XLLP_MFP_ALT_FN_1,
    
    XLLP_MFP_ALT_FN_1,

    XLLP_MFP_ALT_FN_1,

    XLLP_MFP_ALT_FN_1,

    XLLP_MFP_ALT_FN_1,

    XLLP_MFP_ALT_FN_1,
    
    XLLP_MFP_U2D_ULPI_D6_AF,

    XLLP_MFP_U2D_ULPI_D7_AF,

    XLLP_MFP_U2D_ULPI_CLK_AF,        

    XLLP_MFP_ALT_FN_0,
    
    XLLP_MFP_ALT_FN_0,

    XLLP_MFP_ALT_FN_0,


};


#define XLLP_MFP_USB2_DEFAULT_DS    XLLP_MFP_DS_MAX

static XLLP_MFP_DRIVE_STRENGTH_T g_U2DMFPDSList[] =
{    

    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,

    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,

    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,
    
    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,


// 8
    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,

    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,

};
class ZyUSBOTG_ULPI;

class OTGCable: public CMiniThread
{
public:
    
    ZyUSBOTG_ULPI * m_pOTGDevice;
 
    OTGCable(ZyUSBOTG_ULPI * OTGdevice)
    {
        m_pOTGDevice=OTGdevice;
        ThreadStart();
    }
    /// Thread function
    DWORD ThreadRun();

};


enum ULPI_MODE
{
    ULPI_MODE_UNKNOWN,
    ULPI_MODE_LOW_POWER,
    ULPI_MODE_SYNC,
    ULPI_MODE_SERIAL_3,
    ULPI_MODE_SERIAL_6,
    ULPI_MODE_CKA
};
class ZyUSBOTG_ULPI: public USBOTG ,public  CIST
{
    P_XLLP_U2D_REGISTERS_T m_pU2DReg;
    BOOL m_last_vbus;
    CClockManager m_clk_pout;    
    CClockManager m_clk_sidecar;
    OTGCable *m_pCable; 
    XLLP_GPIO_T *m_pGPIO;
    P_XLLP_VUINT32_T m_pMfpRegBase;
    USBOTG_STATES m_OldStatus;

    static LPCTSTR m_OtgStateString[] ;

    DWORD m_StartSRP;

    CLIENT_ID m_IPMID;
    XLLP_OST_T *m_pOST;
    P_XLLP_U2D_REGISTERS_T    m_pU2DStaticAddr ; ///<! Static virtual address for Install ISR
    
    HANDLE m_hParent;

    BOOL m_IsInLowPowerMode; //ULPI Status don't know entry Low power mode if set power mode by software

    HANDLE m_PICHandle;
    
    DWORD m_gpioIrq;
    DWORD m_sysintr_gpio;
    HANDLE m_hGPIOEvent;
    HANDLE m_hOpenContentGPX;        ///< GPIO Expend handle
    DWORD sidecar_disabled_already;
    BOOL m_insertEvent;
    DWORD m_timeout;
    volatile BOOL m_ipmNotifiedD0Rdy;
    CRITICAL_SECTION m_cs;
    //low power mode wakeup source
    P_XLLP_PM_BPMU_T	m_pBPMURegs;

	BOOL m_bResume;

public :
    ULPI_MODE GetCurrentMode()
    {
        if(m_pU2DReg == NULL)
            return ULPI_MODE_UNKNOWN;

        if(m_pU2DReg->u2dotgusr & XLLP_U2DOTGUSR_LPA )
            return ULPI_MODE_LOW_POWER;

        if(m_pU2DReg->u2dotgusr & XLLP_U2DOTGUSR_S3A)
            return ULPI_MODE_SERIAL_3;

        if(m_pU2DReg->u2dotgusr & XLLP_U2DOTGUSR_S6A)
            return ULPI_MODE_SERIAL_6;

        if(m_pU2DReg->u2dotgusr & XLLP_U2DOTGUSR_CKA)
            return ULPI_MODE_CKA;

        return ULPI_MODE_SYNC;
    }

    ZyUSBOTG_ULPI(PTSTR lpActivePath):USBOTG(lpActivePath), CIST(lpActivePath),m_clk_pout(CLKMGR_OSSC_POUT),m_clk_sidecar(CLKMGR_SIDECAR)
    {
        m_pBPMURegs = NULL;
        m_pU2DReg=NULL;
        m_pCable = NULL;
        m_pMfpRegBase=NULL;
        m_pGPIO=NULL;
        m_OldStatus = USBOTG_states_unknown;
        m_insertEvent= FALSE;
        m_hParent =0;
		m_bResume = FALSE;

        m_PICHandle =0;
        m_pOST = NULL;
        m_ipmNotifiedD0Rdy = FALSE;
        m_hParent = CreateBusAccessHandle(lpActivePath);

        m_pU2DStaticAddr = NULL;
        InitializeCriticalSection(&m_cs);

        IPM_STATUS_T status;
        status = IPM_Register(_T("UsbOTG_ULPI:"), &m_IPMID ,3000);
        if ( status==IPM_STATUS_SUCCESS)
        {
            DWORD dwProcState;
            RETAILMSG (1, (_T("[IPM UsbOTG_ULPI] Registration Completed, client id is %d\r\n"),m_IPMID));

            dwProcState = IPM_PROCESSOR_ALL_RDY; // Initial

            // Notify IPM 
            if ( IPM_NotifyReadyForProcState(m_IPMID, dwProcState ,3000)==IPM_STATUS_SUCCESS)
            {
                RETAILMSG(1, (_T("[IPM UsbOTG_ULPI] Notify IPM Ready For Processor state for driver Success!\r\n")));
            }
            else
            {
                RETAILMSG(1, (_T("[IPM UsbOTG_ULPI] Notify IPM Ready For Processor state for driver Fail!\r\n")));
            }
        }
        else
            RETAILMSG(1, (_T("[IPM UsbOTG_ULPI] Registration Failed with error code %d\r\n"),status));


        
    }
    void ULPI_Reset()
    {
#if 0
        if(GPX_SetDirection(XLLP_GPIO_ULPI_RESET, XLLP_GPIO_DIRECTION_OUT) != XLLP_STATUS_SUCCESS)
        {
            RETAILMSG(1, (_T("Set XLLP_GPIO_ULPI_RESET DIR Fail\r\n")));
        }
#endif
        if(GPX_SetOutputLevel(XLLP_GPIO_ULPI_RESET, XLLP_LO) != XLLP_STATUS_SUCCESS)
        {
            RETAILMSG(1, (_T("Set XLLP_GPIO_ULPI_RESET LO FAIL\r\n")));
        }     
    
        Sleep(100);

        if(GPX_SetOutputLevel(XLLP_GPIO_ULPI_RESET, XLLP_HI) != XLLP_STATUS_SUCCESS)
        {
            RETAILMSG(1, (_T("Set XLLP_GPIO_ULPI_RESET HI FAIL\r\n")));
        }     
#if 0        
        if(GPX_SetDirection(XLLP_GPIO_ULPI_RESET, XLLP_GPIO_DIRECTION_IN) != XLLP_STATUS_SUCCESS)
        {
            RETAILMSG(1, (_T("Set XLLP_GPIO_ULPI_RESET DIR Fail\r\n")));
        }
#endif
    }

    
    void CLK_OP(BOOL enable)
    {
        if(enable)
        {
            DBG(TRUE, (_T("CLK_OP:: Enable\r\n")));

            m_clk_pout.enable();
            m_clk_sidecar.enable();
            
        }
        else
        {
            DBG(TRUE, (_T("CLK_OP:: Disable\r\n")));

            m_clk_sidecar.disable();
            m_clk_pout.disable();
        }

    }
    BOOL Init()
    {

        DBG(TRUE, (_T("OTG Init*******10******\r\n")));

        sidecar_disabled_already = 1;  
        CLK_OP(TRUE);
        BSP_ARGS args;
        DWORD size;
        //Get Eboot BSP argument to check if use USB 1.1 as default client
        if(KernelIoControl(IOCTL_GET_BSP_ARGS,NULL,0,&args,sizeof(args),&size))
        {
            if(args.kitl.devLoc.PhysicalLoc == (PVOID)MONAHANS_BASE_REG_PA_USB2H)
            {
                RETAILMSG(1, (_T("EBOOT Config use USB 2.0 as KITL \r\n")));
                return FALSE;
            }
        }
          
        DBG(1, (_T("Init called sidecar enable \r\n")));

        BOOL ret=USBOTG::Init();
        if(!ret)
            return ret;
        m_last_vbus =  FALSE; 
        m_PICHandle=CreateFile(PIC_FILE_NAME, 0, 0, NULL, 0, 0, NULL);
        if( 0 == m_PICHandle )
        {
            DEBUGMSG(ZONE_ERROR, (_T("ERROR: can't open PIC(Arava) driver   Last Error %d.\r\n"),GetLastError() ));
            return FALSE;
        }
#if 0
        BYTE regs[2];
        regs[0]=XLLP_ARAVA_MISCB;
        if(!DeviceIoControl(m_PICHandle, PIC_IO_GET_REG, regs,sizeof(BYTE), regs+1, sizeof(BYTE),NULL,NULL))
        {
            DEBUGMSG(ZONE_ERROR,(_T("Error PIC_IO_GET_REG     Last Error %d.\r\n"),GetLastError() ));
            return FALSE;
        }
        regs[1]|=0xC;
        if(!DeviceIoControl(m_PICHandle, PIC_IO_SET_REG, regs,sizeof(BYTE)*2, NULL,NULL,NULL,NULL))
        {
            DEBUGMSG(ZONE_ERROR,(_T("Error PIC_IO_SET_REG     Last Error %d.\r\n"),GetLastError() ));
            return FALSE;
        }     
#endif

        if (NULL == m_pU2DReg ) 
        {
            PHYSICAL_ADDRESS ioPhysicalBase = {MONAHANS_BASE_REG_PA_USB2H, 0 };
            m_pU2DReg = (P_XLLP_U2D_REGISTERS_T)MmMapIoSpace(ioPhysicalBase, sizeof(XLLP_U2D_REGISTERS_T),FALSE);

            if (NULL == m_pU2DReg)
                return FALSE;            

            ULONG AddressSpace =0 ;
            if (!BusTransBusAddrToStatic( m_hParent,Internal,0, ioPhysicalBase, sizeof(XLLP_U2D_REGISTERS_T),&AddressSpace,(PPVOID) &m_pU2DStaticAddr) ||
                        AddressSpace!=0) 
            {
                m_pU2DStaticAddr = NULL;
                return FALSE;
            }
        
        }
        
        if (NULL == m_pBPMURegs ) 
        {
            PHYSICAL_ADDRESS ioPhysicalBase = {MONAHANS_BASE_REG_PA_BPMU, 0 };
            m_pBPMURegs= (P_XLLP_PM_BPMU_T)MmMapIoSpace(ioPhysicalBase, sizeof(XLLP_PM_BPMU_T),FALSE); //D1/D2 SUPPORT
            
            if (NULL == m_pBPMURegs)
            {
                RETAILMSG(1, (_T("MAP BPMU Register error ")));
                return FALSE;
            }
        }
        

        if (NULL == m_pGPIO  ) 
        {
            PHYSICAL_ADDRESS ioPhysicalBase = {MONAHANS_BASE_REG_PA_GPIO, 0 };
            m_pGPIO = (P_XLLP_GPIO_T)MmMapIoSpace(ioPhysicalBase, sizeof(XLLP_GPIO_T),FALSE);

            if (NULL == m_pGPIO )
                return FALSE;            
        }


        if (NULL == m_pMfpRegBase )
        {
                PHYSICAL_ADDRESS    ioPhysicalBase = { MONAHANS_BASE_REG_PA_MFP, 0};
                m_pMfpRegBase = (P_XLLP_VUINT32_T) MmMapIoSpace(ioPhysicalBase, 0x1000,FALSE);
                if (NULL == m_pMfpRegBase )
                    return FALSE;
        }
        if ( NULL == m_pOST ) 
        {
             PHYSICAL_ADDRESS ioPhysicalBase = {MONAHANS_BASE_REG_PA_OST, 0 };
             m_pOST = (P_XLLP_OST_T)MmMapIoSpace(ioPhysicalBase, sizeof(XLLP_OST_T),FALSE);

             if ( NULL == m_pOST)
                return FALSE;            
        }
             
       
        m_gpioIrq=  IRQ_GPIO_SHARE(GPIO33);
                
        if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &m_gpioIrq, sizeof(DWORD), &(m_sysintr_gpio), sizeof(DWORD), NULL))
        {
            // invalid GPIO intr
            DEBUGMSG(ZONE_ERROR, (TEXT("Error obtaining PowerIC SYSINTR value!\n")));
            return ERROR_INVALID_DATA;
        }
    //    RETAILMSG(TRUE, (_T("Get sysintr for GPIO33 is %d\r\n"),m_sysintr_gpio));
        m_hGPIOEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
        if (m_hGPIOEvent!=NULL)
            InterruptInitialize(m_sysintr_gpio,m_hGPIOEvent, NULL, 0) ;
        else
            return ERROR_INVALID_DATA;
            
        RETAILMSG(TRUE, (_T("OTG Init\r\n")));

        //set ULPI wakeup source
        if ( m_pBPMURegs!= NULL)
        {
            #define AD2D0ER_WEDMUX2 22
            m_pBPMURegs->ad2d0er |= 1ul<<AD2D0ER_WEDMUX2; 
            m_pBPMURegs->ad1d0er |= 1ul<<AD2D0ER_WEDMUX2;                   
        }
        XllpMfpSetAfDs_List(m_pMfpRegBase, 
                    g_U2DMFPList,
                    g_U2DMFPDeviceAF,
                    g_U2DMFPDSList);
        ULPI_Reset();
        SwitchToSyncMode();

        m_pU2DReg->u2dotgicr = XLLP_U2DOTGICR_ALLOTG ;
        m_pU2DReg->u2dotgcr |= XLLP_U2DOTGCR_OTGEN;

        
        DWORD value = 0;

        m_UsbOtgInput.bit.id = value&XLLP_U2DOTGUSR_ID? 1:0;
        m_UsbOtgInput.bit.b_sess_end =value&XLLP_U2DOTGUSR_SE?1:0;
        m_UsbOtgInput.bit.a_sess_vld = m_UsbOtgInput.bit.b_sess_vld = value&XLLP_U2DOTGUSR_SV?1:0;
        m_UsbOtgInput.bit.a_vbus_vld=value&XLLP_U2DOTGUSR_VV?1:0;
        
        EventNotification();

        
        GIISR_INFO Info;
        Info.SysIntr = CIST::GetSysIntr();
        Info.CheckPort = TRUE;
        Info.PortIsIO = FALSE;
        Info.UseMaskReg = FALSE;
        Info.PortAddr = ( DWORD ) &(m_pU2DStaticAddr->u2dotgisr); // Offset to udc_otgisr
        Info.Mask = 0x1FFFF;
        Info.PortSize = sizeof( DWORD );

        RETAILMSG(1, (L"*Installed ISR- 0x%X\r\n", Info.PortAddr));
        if ( !IntChainHandlerIoControl( IOCTL_GIISR_INFO,&Info, sizeof( Info ), NULL, 0, NULL ) )
        {
            return  FALSE;
        }
            
        IntializeInterrupt(NULL, NULL);
 
        ThreadStart();
        if((m_pU2DReg->u2dotgusr & XLLP_U2DOTGUSR_VV) ||((~m_pU2DReg->u2dotgusr) & XLLP_U2DOTGUSR_ID))
            m_timeout = INFINITE;
        else
            m_timeout= 5000;

        m_pCable=new OTGCable(this);         

        if((m_pU2DReg->u2dotgusr & XLLP_U2DOTGUSR_VV) ||((~m_pU2DReg->u2dotgusr) & XLLP_U2DOTGUSR_ID))
        {      
 
            DBG(1, (L"*****CABLE ON , WILL SET EVENT\r\n"));
            SetEvent(m_hGPIOEvent);
        }
        return TRUE;
    }    

    BOOL ReadULPIReg(BYTE reg,BYTE *value)
    {
        if(GetCurrentMode()!= ULPI_MODE_SYNC )
        {
            DBG(1,(_T("ULPI Mode Error, current mode is %d\r\n"),GetCurrentMode()));
            return FALSE;
        }
        
        if(!(m_pU2DReg->u2dotgcr & XLLP_U2DOTGCR_ULE))
            m_pU2DReg->u2dotgcr |= XLLP_U2DOTGCR_ULE;

        int i=0;
        m_pU2DReg->u2dotgucr = XLLP_U2DOTGUCR_RUN|XLLP_U2DOTGUCR_RNW|(reg<<XLLP_U2DOTGUCR_ADDR_SHIFT);
        while(m_pU2DReg->u2dotgucr & XLLP_U2DOTGUCR_RUN)
        {
            i++;
            if(i>10000000)
            {
                RETAILMSG(1,(L"Read ULPI register Time out\r\n"));
                return FALSE;
            }
        }
        *value=(BYTE)(m_pU2DReg->u2dotgucr & 0xFF);

        DBG(1,(_T("ULPI Read 0x%x  value 0x%x\r\n"), reg, *value));

        return TRUE;
    }

    BOOL WriteULPIReg(BYTE reg, BYTE value)
    {
        DBG(1,(_T("ULPI Write 0x%x  value 0x%x\r\n"), reg, value));

        if(GetCurrentMode()!= ULPI_MODE_SYNC )
        {
            DBG(1,(_T("ULPI Mode Error, Current mode is %d\r\n"),GetCurrentMode()));
            SwitchToSyncMode();
            m_pU2DReg->u2dotgicr = XLLP_U2DOTGICR_ALLOTG ;
        }
        if(!(m_pU2DReg->u2dotgcr & XLLP_U2DOTGCR_ULE))
        {
            DBG(1,(_T("ULPI ULE setting\r\n")));
            m_pU2DReg->u2dotgcr |= XLLP_U2DOTGCR_ULE;
        }

        int i=0;
        m_pU2DReg->u2dotgucr = XLLP_U2DOTGUCR_RUN|(reg<<XLLP_U2DOTGUCR_ADDR_SHIFT) |(value<<XLLP_U2DOTGUCR_WDATA_SHIFT);
        while(m_pU2DReg->u2dotgucr & XLLP_U2DOTGUCR_RUN)
        {
            i++;
            if(i>10000000)
            {

                RETAILMSG(1,(L"Write ULPI register Time out\r\n"));
                ULPI_Reset();
                return TRUE;
            }
        }

        return TRUE;
    }
    ~ZyUSBOTG_ULPI()
    {
        
        if ( IPM_DeRegister(m_IPMID,3000)==IPM_STATUS_SUCCESS)
            RETAILMSG(1, (_T("[IPM USBOTG] De-Registration Completed OK\n")));
        else
            RETAILMSG(1, (_T("[IPM USBOTG] De-Registration FAILED\n")));

    
        if(m_PICHandle)
        {
            CloseHandle(m_PICHandle);
            m_PICHandle=0;
        }
         if( m_pCable )
           {
                delete m_pCable;
                m_pCable=NULL;
           }
        if(m_pU2DReg)
        {
            MmUnmapIoSpace((PVOID)m_pU2DReg,0);
            m_pU2DReg=NULL;
        }
        if(m_pGPIO)
        {
            MmUnmapIoSpace((PVOID)m_pGPIO,0);
            m_pGPIO=NULL;
            
        }
        if(m_pMfpRegBase)
        {
            MmUnmapIoSpace((PVOID)m_pMfpRegBase,0);
            m_pMfpRegBase=NULL;                
        }

        if (m_pBPMURegs!=NULL) 
        {
            
            MmUnmapIoSpace((PVOID)m_pBPMURegs,0UL);
            m_pBPMURegs=NULL;
        }
        
        if(m_pOST)
        {
            MmUnmapIoSpace((PVOID)m_pOST,0);
            m_pOST=NULL;

        }    
    
    } 
    private:
    void DumpReg()
    {

        DBG(1,(_T("U2D u2dctrl 0x%x \r\n"), m_pU2DReg->u2dctrl));
        DBG(1,(_T("U2D u2dicr 0x%x \r\n"), m_pU2DReg->u2dicr));
        DBG(1,(_T("U2D u2dotgcr 0x%x \r\n"), m_pU2DReg->u2dotgcr));
        DBG(1,(_T("U2D u2dotgusr 0x%x \r\n"), m_pU2DReg->u2dotgusr));
        BYTE value;
        ReadULPIReg(ULPI_FUNCTION, &value);
        DBG(1,(_T("ULPI_FUNCTION 0x%x \r\n"),value));
        ReadULPIReg(ULPI_INTERFACE, &value);
        DBG(1,(_T("ULPI_INTERFACE 0x%x \r\n"),value));
        ReadULPIReg(ULPI_OTG, &value);
        DBG(1,(_T("ULPI_OTG 0x%x \r\n"),value));
        ReadULPIReg(ULPI_USB_INTR_EN_RISING, &value);
        DBG(1,(_T("ULPI_USB_INTR_EN_RISING 0x%x \r\n"),value));
        ReadULPIReg(ULPI_USB_INTR_EN_FALLING, &value);
        DBG(1,(_T("ULPI_USB_INTR_EN_FALLING 0x%x \r\n"),value));

        

    }

    void EnableLowPowerIntr(BOOL enable)
    {

        if(enable)
        { 
            m_pU2DReg->u2dotgicr = 0; 
            SwtichToLowPowerMode();
            m_pU2DReg->u2dotgcr &= ~(XLLP_U2DOTGCR_ULAF);
            DBG(1,(_T("after clear ULAF, the m_pU2DReg->u2dotgusr is %x ****** \r\n"),m_pU2DReg->u2dotgusr));          
            
            XllpMfpSetAfDs(m_pMfpRegBase,  XLLP_MFP_U2D_ULPI_D3_OFFSET,  XLLP_MFP_ALT_FN_0 ,  XLLP_MFP_DS_01X);
            XllpGpioSetDirection(m_pGPIO,  XLLP_MFP_U2D_ULPI_D3_OFFSET,    XLLP_GPIO_DIRECTION_IN); 
            //enable interrupt
            XllpGpioSetRisingEdgeDetectEnable(m_pGPIO,GPIO33,XLLP_ON); 
            m_UsbOtgInput.bit.b_sess_end = 1;
        }
        else
        {

            m_pU2DReg->u2dotgicr = XLLP_U2DOTGICR_ALLOTG;
            XllpGpioSetRisingEdgeDetectEnable(m_pGPIO,GPIO33,XLLP_OFF);
            XllpMfpSetAfDs_List(m_pMfpRegBase, 
                    g_U2DMFPList,
                    g_U2DMFPDeviceAF,
                    g_U2DMFPDSList);
        }

    }

    void SwitchToSyncMode()
    {
    
        unsigned long m_count=0;    

        unsigned long  U2DOTGCR=0;
        
        m_pU2DReg->u2dctrl &= ~XLLP_U2DCR_UDE;
        m_pU2DReg->u2dotgcr &= ~XLLP_U2DOTGCR_ULE;
        m_pU2DReg->u2dotgcr |= XLLP_U2DOTGCR_UTMID;

        m_pU2DReg->u2dotgcr |= XLLP_U2DOTGCR_RTSM ;
        U2DOTGCR = m_pU2DReg->u2dotgcr ;
        U2DOTGCR|= XLLP_U2DOTGCR_ULAF;
        U2DOTGCR &= ~XLLP_U2DOTGCR_SMAF;
        U2DOTGCR &= ~XLLP_U2DOTGCR_CKAF;
        m_pU2DReg->u2dotgcr = U2DOTGCR;
        m_pU2DReg->u2dotgcr |= XLLP_U2DOTGCR_ULE;
        DBG(1,(_T("++switch to sync mode \r\n")));

        while(m_pU2DReg->u2dotgusr & 0xF0000000)
        {
            m_count++;
            Sleep(2);
            
            if(m_count>500)
            {
                RETAILMSG(1,(_T("*******ULPI reset!!! \r\n")));
                ULPI_Reset();
                return;
            }
        }

        
    }

    void SwtichToLowPowerMode()
    {
        DBG(1,(_T("In SwtichToLowPowerMode \r\n")));

        SwitchToSyncMode();
        WriteULPIReg(ULPI_INTERFACE_SET,ULPI_INTERFACE_PROTECT_DISABLE);
        WriteULPIReg(ULPI_USB_INTR_EN_RISING_CLR, ULPI_USB_INTR_HOSTDIS |ULPI_USB_INTR_SESS_END);    
        WriteULPIReg(ULPI_USB_INTR_EN_FALLING_CLR, ULPI_USB_INTR_HOSTDIS | ULPI_USB_INTR_SESS_END);    
        //enable VV, ID interrupt
        WriteULPIReg(ULPI_USB_INTR_EN_RISING_SET, ULPI_USB_INTR_VBUS_VALID | ULPI_USB_INTR_ID| ULPI_USB_INTR_SESS_VALID);    
        WriteULPIReg(ULPI_USB_INTR_EN_FALLING_SET, ULPI_USB_INTR_VBUS_VALID | ULPI_USB_INTR_ID| ULPI_USB_INTR_SESS_VALID);
        
        WriteULPIReg(ULPI_FUNCTION_CLR, ULPI_FUNCTION_SUSPENDM);
#ifdef ULPI_DEBUG        
        if(m_pU2DReg->u2dotgusr & 0x80000000)    
            DBG(1,(_T("In SwtichToLowPowerMode \r\n")));
        else
            DBG(1,(_T("ERR SwtichToLowPowerMode usr is %x \r\n"),m_pU2DReg->u2dotgusr ));
#endif        
    }
    void SwtichToSerialMode(BOOL Is6Pin,BOOL charge_vbus)
    {
        DBG(1,(_T("In SwtichToSerialModeMode \r\n")));
        SwitchToSyncMode();
        m_pU2DReg->u2dotgicr = 0;//XLLP_U2DOTGICR_ALLOTG;
        if(charge_vbus)
        {
            WriteULPIReg(ULPI_USB_INTR_EN_RISING_CLR, ULPI_USB_INTR_VBUS_VALID | ULPI_USB_INTR_SESS_VALID | ULPI_USB_INTR_SESS_END |ULPI_USB_INTR_HOSTDIS);    
            WriteULPIReg(ULPI_USB_INTR_EN_FALLING_CLR,ULPI_USB_INTR_VBUS_VALID | ULPI_USB_INTR_SESS_VALID | ULPI_USB_INTR_SESS_END |ULPI_USB_INTR_HOSTDIS);
        
        }
        else
        {
            WriteULPIReg(ULPI_USB_INTR_EN_RISING_CLR, ULPI_USB_INTR_VBUS_VALID | ULPI_USB_INTR_SESS_VALID | ULPI_USB_INTR_SESS_END |ULPI_USB_INTR_HOSTDIS);    
            WriteULPIReg(ULPI_USB_INTR_EN_FALLING_CLR,  ULPI_USB_INTR_HOSTDIS);
        
        }
        unsigned long count=0;
        while(m_pU2DReg->u2dotgusr & 0xf0000000) count++;
        DBG(1,(_T("++RT_SyncModeU2D u2dotgusr 0x%x, count is %x\r\n"), m_pU2DReg->u2dotgusr,count));

        WriteULPIReg(ULPI_FUNCTION, 0x41);
        
        if(Is6Pin)
        {
            m_pU2DReg->u2dp3cr &=  ~(0x1<<XLLP_U2DP3CR_P2SS_SHIFT);
            m_pU2DReg->u2dp3cr &=  ~(0x1<<9);
            
            WriteULPIReg(ULPI_INTERFACE_CLR, ULPI_INTERFACE_3_PIN);
            WriteULPIReg(ULPI_INTERFACE_SET, ULPI_INTERFACE_6_PIN);        

        }
        else
        {
            m_pU2DReg->u2dp3cr |= (0x1<<XLLP_U2DP3CR_P2SS_SHIFT);

            WriteULPIReg(ULPI_INTERFACE_CLR, ULPI_INTERFACE_6_PIN);
            WriteULPIReg(ULPI_INTERFACE, ULPI_INTERFACE_3_PIN);
            
        }

        // Change UTMID
        m_pU2DReg->u2dctrl &= ~XLLP_U2DCR_UDE;

        m_pU2DReg->u2dotgcr&=~XLLP_U2DOTGCR_ULAF;
        m_pU2DReg->u2dotgcr&=~XLLP_U2DOTGCR_CKAF;
        m_pU2DReg->u2dotgcr&=~XLLP_U2DOTGCR_ULE;

        m_pU2DReg->u2dotgcr|=XLLP_U2DOTGCR_UTMID;

        m_pU2DReg->u2dotgcr|=XLLP_U2DOTGCR_SMAF;
        
        DBG(1, (_T("Switch to SerialMode\r\n")));

        XllpMfpSetAfDs_List(m_pMfpRegBase, 
                    g_U2DMFPList,
                    g_U2DMFPHostAF,
                    g_U2DMFPDSList);
        m_pU2DReg->u2dotgicr |= XLLP_U2DOTGICR_IESI;
    }
    
    virtual BOOL OTGNotifyDetach(LPCTSTR lpDeviceName) 
    {
        DBG(1, (_T("[ULPI]: OTGNotifyDetach\r\n")));
        BOOL b=USBOTG::OTGNotifyDetach(lpDeviceName);
        //if(!b)
        //    return b;

		if(m_UsbOtgState != USBOTG_a_suspend)
		{
			m_pU2DReg->u2dotgicr = XLLP_U2DOTGICR_ALLOTG;
			WriteULPIReg(ULPI_USB_INTR_EN_RISING_SET, ULPI_USB_INTR_VBUS_VALID | ULPI_USB_INTR_SESS_VALID | ULPI_USB_INTR_SESS_END);    
			WriteULPIReg(ULPI_USB_INTR_EN_FALLING_SET, ULPI_USB_INTR_VBUS_VALID | ULPI_USB_INTR_SESS_VALID | ULPI_USB_INTR_SESS_END);
		}

		if(m_UsbOtgState == USBOTG_b_host)
		{
			m_UsbOtgInput.bit.b_bus_req = 0;
		}

        m_UsbOtgInput.bit.b_conn=0;
        m_UsbOtgInput.bit.a_conn=0;
        
        EventNotification();
        return TRUE;
    }


    BOOL OTGHCDNotfyAccept(LPCTSTR lpDeviceName, BOOL fAccept)
    {

        BOOL b=USBOTG::OTGHCDNotfyAccept(lpDeviceName,fAccept);
        if(!b)
            return b;

        m_UsbOtgInput.bit.a_conn=fAccept;
        
        EventNotification();
        return TRUE;
    }
    BOOL ISTTimeout()
    {
        return ISTProcess(); //for debug only
    }
    
    BOOL NotifyClientDriver(DWORD code)
    {
                    //HANDLE hHandle=pDevice->GetDeviceHandle();
            HANDLE hHandle=CreateFile(TEXT("UFN1:"),
                                                    DEVACCESS_BUSNAMESPACE,
                                                    FILE_SHARE_READ | FILE_SHARE_WRITE,
                                                    NULL,
                                                    OPEN_EXISTING,
                                                    0,
                                                    NULL);
			if(INVALID_HANDLE_VALUE == hHandle)
			{
				return FALSE;
			}

            DWORD size;
			BOOL ret = DeviceIoControl(hHandle, code, NULL, 0, NULL, 0, &size, NULL);
			CloseHandle(hHandle);

            return ret;
    }

    DWORD CableDetectHandle(BOOL CABLE_ATTACH)
    {           
  
        DBG(1, (_T("USB2.0 Cable %d\r\n"), CABLE_ATTACH));
        if(CABLE_ATTACH)
        {
            EnterCriticalSection(&m_cs);
            CLK_OP(TRUE);
            if (!m_ipmNotifiedD0Rdy)
            {
                if ( IPM_SetMinOp(m_IPMID,IPM_OP_104MHZ, 3000) != IPM_STATUS_SUCCESS)
                    RETAILMSG(1, (_T("USBOTG: IPM_SetMinOp failed\r\n")));
                DWORD dwProcState = IPM_PROCESSOR_D0_RDY; 
    
                // Notify IPM 
                if ( IPM_NotifyReadyForProcState(m_IPMID, dwProcState ,3000)==IPM_STATUS_SUCCESS)
                {
                    DEBUGMSG(1, (_T("[IPM UsbOTG_ULPI] Notify IPM Ready For Processor state for driver Success!\r\n")));
                }
                else
                {
                    RETAILMSG(1, (_T("[IPM UsbOTG_ULPI] Notify IPM Ready For Processor state for driver Fail!\r\n")));
                }
                
                m_ipmNotifiedD0Rdy = TRUE;
            }
            LeaveCriticalSection(&m_cs);
                   
            DBG(1, (_T("CabledetectHandle called sidecar enable \r\n")));

            EnableLowPowerIntr(FALSE);              

        }
        else
        {
            DBG(1, (_T("CabledetectHandle called sidecar Disable \r\n")));
                 
            EnableLowPowerIntr(TRUE);
            if ( IPM_ReleaseMinOp(m_IPMID, 3000) != IPM_STATUS_SUCCESS)
                RETAILMSG(1, (_T("USBOTG: IPM_ReleaseMinOp failed\r\n")));
            
            DWORD dwProcState = IPM_PROCESSOR_ALL_RDY; // Initial; // Initial

            // Notify IPM 
            if ( IPM_NotifyReadyForProcState(m_IPMID, dwProcState ,3000)==IPM_STATUS_SUCCESS)
            {
                DEBUGMSG(1, (_T("[IPM UsbOTG_ULPI] Notify IPM Ready For Processor state for driver Success!\r\n")));
            }
            else
            {
                RETAILMSG(1, (_T("[IPM UsbOTG_ULPI] Notify IPM Ready For Processor state for driver Fail!\r\n")));
            }    
                        
            CLK_OP(FALSE);
        
            EnterCriticalSection(&m_cs);
            m_ipmNotifiedD0Rdy = FALSE;
            LeaveCriticalSection(&m_cs);
            //keep ULPI_STP low during D2
            m_pMfpRegBase[0x040C/4]=0x40;
        }
      
        return 0;
    
    }
    public:     DWORD CableIST()
    {
        CeSetThreadPriority(GetCurrentThread(), 1);
        DWORD r_event;
      
        if(m_hGPIOEvent)
        {
            while(1)
            {
                DBG(1, (TEXT("CableIST :: cable IST waiting\r\n")));
                r_event = WaitForSingleObject(m_hGPIOEvent,m_timeout);
                if(r_event == WAIT_FAILED)
                {
                    DBG(1, (TEXT("*******Wait for object fails is %d**********\r\n"),GetLastError()));
                }
                else
                {
                    DWORD data = GetEventData(m_hGPIOEvent);
                    DBG(1, (_T("GET EVENT result: 0x%x\r\n"), data));
                    if(0== data)
                    {
                        switch (r_event){
                            
                        case WAIT_OBJECT_0:
                            if(!data)
                                CableDetectHandle(TRUE);
                            InterruptDone(m_sysintr_gpio);
                            break;
                        case WAIT_TIMEOUT:
                            DBG(1, (TEXT("-----------CableIST :: Timeout event\r\n")));
                            if((m_pU2DReg->u2dotgusr & XLLP_U2DOTGUSR_VV) ||((~m_pU2DReg->u2dotgusr) & XLLP_U2DOTGUSR_ID))
                            {
                                DBG(1, (TEXT("-----------CableIST :: True\r\n")));
                                CableDetectHandle(TRUE);
                            }
                            else
                            {
                                DBG(1, (TEXT("-----------CableIST :: False\r\n")));
                                CableDetectHandle(FALSE);
                            }
                            m_timeout = INFINITE;
							InterruptDone(m_sysintr_gpio);
                            break;
                        default:                            
                            DBG(1, (TEXT("CableIST :: Err event\r\n")));
                            ASSERT(FALSE);
                            break;
                        }
                
                    }
                    else
                    {
                        m_timeout= data;
                        SetEventData(m_hGPIOEvent,0);
                    }
                }
            }
            return 0;
        }
        else
        {     
            DBG(1, (TEXT("CableIST :: invalid event\r\n")));  
            return 0;
        }
    }


    BOOL    ISTProcess()
    {

        unsigned char m_usr;
        while(!IsAPIReady(SH_SHELL))
        {
            Sleep(1000);
        }

		if(m_bResume)
		{
			m_bResume = FALSE;
			Sleep(5000);
		}

        EnterCriticalSection(&m_cs);
        CLK_OP(TRUE);
         
        LeaveCriticalSection(&m_cs);

        DWORD data;    
        data=m_pU2DReg->u2dotgisr;    
        m_pU2DReg->u2dotgisr=data;
        DWORD OTGUSR = m_pU2DReg->u2dotgusr;

        DBG(1, (_T("---U2D OTGISR 0x%x otgusr 0x%x \r\n"),data, OTGUSR));
        if( data & XLLP_U2DOTGICR_IESI )
        {
            DBG(1, (_T("[OTG ULPI]:Will set Sync mode \r\n")));

            SwitchToSyncMode(); 

            WriteULPIReg(ULPI_USB_INTR_EN_RISING_SET, ULPI_USB_INTR_VBUS_VALID | ULPI_USB_INTR_SESS_VALID | ULPI_USB_INTR_SESS_END);    
            WriteULPIReg(ULPI_USB_INTR_EN_FALLING_SET, ULPI_USB_INTR_VBUS_VALID | ULPI_USB_INTR_SESS_VALID | ULPI_USB_INTR_SESS_END);
                
        }
        if((data & XLLP_U2DOTGICR_IFEVV) && ((~OTGUSR) & XLLP_U2DOTGUSR_VV))
        {    
            DBG(1, (_T("[OTG ULPI]:***switch to sync mode due to IFEVV**** \r\n")));
            SwitchToSyncMode(); 
        }

		Sleep(50);
          
        ReadULPIReg(ULPI_USB_INTR_STATUS, &m_usr);
        DBG(1, (_T("*U2D OTGISR 0x%x otgusr 0x%x \r\n"),data,m_usr ));

		if(m_ISTTimeout == 1000)
		{
			m_UsbOtgInput.bit.id = 1;
		}
		else
		{
			m_UsbOtgInput.bit.id = m_pU2DReg->u2dotgusr&XLLP_U2DOTGUSR_ID?1:0;
		}

        m_UsbOtgInput.bit.a_sess_vld=m_UsbOtgInput.bit.b_sess_vld = m_pU2DReg->u2dotgusr&XLLP_U2DOTGUSR_SV?1:0;
        if(!m_UsbOtgInput.bit.id)
        {
            m_UsbOtgInput.bit.a_srp_det = m_pU2DReg->u2dotgusr&XLLP_U2DOTGUSR_SV?1:0;

            DBG(1, (_T("***U2D m_UsbOtgInput.bit.a_srp_det 0x%x \r\n"),m_UsbOtgInput.bit.a_srp_det ));
        }
        m_UsbOtgInput.bit.a_vbus_vld=m_pU2DReg->u2dotgusr&XLLP_U2DOTGUSR_VV?1:0;
        m_UsbOtgInput.bit.b_sess_end=m_pU2DReg->u2dotgusr&XLLP_U2DOTGUSR_SE?1:0;    
        
        EventNotification();

		if(m_UsbOtgState == USBOTG_b_idle)
		{
		    if(m_ISTTimeout == INFINITE)
			{
				m_ISTTimeout = 1000;
			}
			else
			{
				m_ISTTimeout = INFINITE;
			}
		}
		else
		{
			m_ISTTimeout = INFINITE;
		}

        return TRUE;
    } 


    BOOL    NewStateAction(USBOTG_STATES usbOtgState , USBOTG_OUTPUT usbOtgOutput ) 
    {
        
        if( !USBOTG::NewStateAction(usbOtgState,usbOtgOutput))
        {
            return FALSE;
        }
        
        if(usbOtgState==m_OldStatus)
        {
            return TRUE;
        }
        m_OldStatus=usbOtgState;
        RETAILMSG(1,(_T("OTGSTATE:%s\r\n"),m_OtgStateString[usbOtgState]));

        m_SyncAccess.Lock();

        USBOTG_OUTPUT lusbOtgOutput = usbOtgOutput;
        XLLP_VUINT32_T up2ocr=0;

        if( usbOtgOutput.bit.loc_sof )
        {
            m_pU2DReg->u2dctrl= 0;
            m_UsbOtgInput.bit.a_srp_det = 0;    
            if(usbOtgState == USBOTG_a_host)
                SwtichToSerialMode(TRUE,TRUE);
            else
                SwtichToSerialMode(TRUE,FALSE);
        }
        else
        {
            if( usbOtgState == USBOTG_b_peripheral )
            { 
                DBG(1, (_T("USBOTG: set function pin\r\n")));
                if(GetCurrentMode()!= ULPI_MODE_SYNC)
                {
                    RETAILMSG(1, (_T("USBOTG: current mode is %d\r\n"),GetCurrentMode()));
                    SwitchToSyncMode();
                }
                WriteULPIReg(ULPI_OTG_CLR, ULPI_OTG_DMPULLDOWN|ULPI_OTG_DPPULLDOWN);    
                m_pU2DReg->u2dotgicr = 0;
                m_pU2DReg->u2dctrl &=~XLLP_U2DCR_UDE;
                m_pU2DReg->u2dotgcr &=~XLLP_U2DOTGCR_ULE;     
                unsigned long U2DOTGCR = m_pU2DReg->u2dotgcr;
                U2DOTGCR &=~(XLLP_U2DOTGCR_UTMID | XLLP_U2DOTGCR_SMAF);     
                m_pU2DReg->u2dotgcr = U2DOTGCR;
                m_pU2DReg->u2dotgcr |=XLLP_U2DOTGCR_ULE; 
                m_pU2DReg->u2dotgicr = XLLP_U2DOTGICR_IESI|XLLP_U2DOTGICR_IESF|XLLP_U2DOTGICR_IREID|XLLP_U2DOTGICR_IRESE\
                                      |XLLP_U2DOTGICR_IRESV|XLLP_U2DOTGICR_IFEID|XLLP_U2DOTGICR_IFESE|XLLP_U2DOTGICR_IFESV;

                DeviceFolder * pDevice = GetChildByDeviceNumber(USBOTG_USBFN_DRIVER_DEVICE_INDEX) ;
                BOOL b=pDevice->IsDriverLoaded();
                DBG(1, (_T("USBOTG: before reset controller , u2dcr is %x\r\n"),m_pU2DReg->u2dctrl));
                NotifyClientDriver(IOCTL_UFN_RESET_CONTROLLER);
                DBG(1, (_T("Device 0x%x Is Loaded %d\r\n"), pDevice, b));      
            }
            
            if(usbOtgState == USBOTG_a_peripheral)
            {
                DBG(1, (_T("USBOTG: set function pin\r\n")));
                if(GetCurrentMode()!= ULPI_MODE_SYNC)
                {
                    RETAILMSG(1, (_T("USBOTG: current mode is %d\r\n"),GetCurrentMode()));
                    SwitchToSyncMode();
                }
                WriteULPIReg(ULPI_OTG_CLR, ULPI_OTG_DPPULLDOWN);
                WriteULPIReg(ULPI_OTG_SET, ULPI_OTG_DMPULLDOWN);
    
                m_pU2DReg->u2dotgicr = 0;
                m_pU2DReg->u2dctrl &=~XLLP_U2DCR_UDE;
                m_pU2DReg->u2dotgcr &=~XLLP_U2DOTGCR_ULE;     
                unsigned long U2DOTGCR = m_pU2DReg->u2dotgcr;
                U2DOTGCR &=~(XLLP_U2DOTGCR_UTMID | XLLP_U2DOTGCR_SMAF);     
                m_pU2DReg->u2dotgcr = U2DOTGCR;
                m_pU2DReg->u2dotgcr |=XLLP_U2DOTGCR_ULE; 
                m_pU2DReg->u2dotgicr = XLLP_U2DOTGICR_ALLOTG;
    
                DeviceFolder * pDevice = GetChildByDeviceNumber(USBOTG_USBFN_DRIVER_DEVICE_INDEX) ;
                BOOL b=pDevice->IsDriverLoaded();

                DBG(1, (_T("USBOTG: before reset controller , u2dcr is %x\r\n"),m_pU2DReg->u2dctrl));

                NotifyClientDriver(IOCTL_UFN_RESET_CONTROLLER);
                DBG(1, (_T("Device 0x%x Is Loaded %d\r\n"), pDevice, b));
                
            }
        }
        

        if(usbOtgState == USBOTG_a_idle)
        {

            m_UsbOtgInput.bit.a_bus_req = 0;
            NotifyClientDriver(IOCTL_UFN_STOP_CONTROLLER);
            SwitchToSyncMode();
            WriteULPIReg(ULPI_OTG_SET, ULPI_OTG_DMPULLDOWN|ULPI_OTG_DPPULLDOWN);
            m_UsbOtgInput.bit.a_sess_vld=m_UsbOtgInput.bit.b_sess_vld=m_pU2DReg->u2dotgusr&XLLP_U2DOTGUSR_VV?1:0;
            m_UsbOtgInput.bit.a_bus_req = 1;
        }
		if(usbOtgState == USBOTG_a_wait_vrise)
		{
			BYTE regs[2];
			regs[0]=XLLP_MICCO_MISC;
			if(!DeviceIoControl(m_PICHandle, PIC_IO_GET_REG, regs,sizeof(BYTE), regs+1, sizeof(BYTE),NULL,NULL))
			{
				DEBUGMSG(ZONE_ERROR,(_T("Error PIC_IO_GET_REG     Last Error %d.\r\n"),GetLastError() ));
				return FALSE;
			}
			regs[1]&=~XLLP_MICCO_MISC_USBCP_EN;
			if(!DeviceIoControl(m_PICHandle, PIC_IO_SET_REG, regs,sizeof(BYTE)*2, NULL,NULL,NULL,NULL))
			{
				DEBUGMSG(ZONE_ERROR,(_T("Error PIC_IO_SET_REG     Last Error %d.\r\n"),GetLastError() ));
				return FALSE;
			}
			regs[1]|=XLLP_MICCO_MISC_USBCP_EN;
			if(!DeviceIoControl(m_PICHandle, PIC_IO_SET_REG, regs,sizeof(BYTE)*2, NULL,NULL,NULL,NULL))
			{
				DEBUGMSG(ZONE_ERROR,(_T("Error PIC_IO_SET_REG     Last Error %d.\r\n"),GetLastError() ));
				return FALSE;
			}

			Sleep(200);
		}
		if(usbOtgState == USBOTG_a_wait_vfall)
		{
			BYTE regs[2];
			regs[0]=XLLP_MICCO_MISC;
			if(!DeviceIoControl(m_PICHandle, PIC_IO_GET_REG, regs,sizeof(BYTE), regs+1, sizeof(BYTE),NULL,NULL))
			{
				DEBUGMSG(ZONE_ERROR,(_T("Error PIC_IO_GET_REG     Last Error %d.\r\n"),GetLastError() ));
				return FALSE;
			}
			regs[1]&=~XLLP_MICCO_MISC_USBCP_EN;
			if(!DeviceIoControl(m_PICHandle, PIC_IO_SET_REG, regs,sizeof(BYTE)*2, NULL,NULL,NULL,NULL))
			{
				DEBUGMSG(ZONE_ERROR,(_T("Error PIC_IO_SET_REG     Last Error %d.\r\n"),GetLastError() ));
				return FALSE;
			}

			Sleep(200);

			m_UsbOtgInput.bit.a_sess_vld = 0;
			m_UsbOtgInput.bit.b_conn = 0;
		}
		if(usbOtgState == USBOTG_a_vbus_err)
		{
			m_UsbOtgInput.bit.a_clr_err = 1;
		}
        if( usbOtgState ==USBOTG_b_idle)
        {
            m_UsbOtgInput.bit.b_sess_end = 1;
            m_UsbOtgInput.bit.b_bus_req = 0;
            NotifyClientDriver(IOCTL_UFN_STOP_CONTROLLER);
            m_pU2DReg->u2dotgisr = 0xffffffff;    

            if((m_pU2DReg->u2dotgusr & XLLP_U2DOTGUSR_VV) ||((~m_pU2DReg->u2dotgusr) & XLLP_U2DOTGUSR_ID))
            {
                
            }
            else
            {
                SetEventData(m_hGPIOEvent, 100);
                SetEvent(m_hGPIOEvent);
            }
            
        
        }
        if(usbOtgState ==USBOTG_a_host)
        {
            m_UsbOtgInput.bit.a_bus_req = 1;
        }

        if(usbOtgState ==USBOTG_a_suspend)
        {

            SwitchToSyncMode();
            //enable all interrupt
            WriteULPIReg(ULPI_USB_INTR_EN_RISING_SET, ULPI_USB_INT_OTGALL);    
            WriteULPIReg(ULPI_USB_INTR_EN_FALLING_SET, ULPI_USB_INT_OTGALL);
            WriteULPIReg(ULPI_OTG_SET, ULPI_OTG_DMPULLDOWN|ULPI_OTG_DPPULLDOWN);

            m_pU2DReg->u2dotgicr = 0;
            m_pU2DReg->u2dctrl &=~XLLP_U2DCR_UDE;
            m_pU2DReg->u2dotgcr &=~XLLP_U2DOTGCR_ULE;     
            unsigned long U2DOTGCR = m_pU2DReg->u2dotgcr;
            U2DOTGCR &=~(XLLP_U2DOTGCR_UTMID | XLLP_U2DOTGCR_SMAF);     
            m_pU2DReg->u2dotgcr = U2DOTGCR;
            m_pU2DReg->u2dotgcr |=XLLP_U2DOTGCR_ULE; 
            m_pU2DReg->u2dotgicr = XLLP_U2DOTGICR_ALLOTG;
    
            DeviceFolder * pDevice = GetChildByDeviceNumber(USBOTG_USBFN_DRIVER_DEVICE_INDEX) ;
            BOOL b=pDevice->IsDriverLoaded();

            DBG(1, (_T("USBOTG: before reset controller , u2dcr is %x\r\n"),m_pU2DReg->u2dctrl));
            DBG(1, (_T("USBOTG_a_suspend: b_bus_resume = %x,a_bus_req=%d, a_set_b_hnp_en=%x\r\n"),m_UsbOtgInput.bit.b_bus_resume,m_UsbOtgInput.bit.a_bus_req,m_UsbOtgInternal.bit.a_set_b_hnp_en));            

            NotifyClientDriver(IOCTL_UFN_RESET_CONTROLLER);            

        }

		if(usbOtgState == USBOTG_b_wait_acon)
		{
			SwitchToSyncMode();
            WriteULPIReg(ULPI_OTG_SET, ULPI_OTG_DMPULLDOWN|ULPI_OTG_DPPULLDOWN);
		}

        BOOL vbus=usbOtgOutput.bit.drv_vbus;
#if 0
        if(m_last_vbus != vbus)
        {
            m_last_vbus = vbus;
            DeviceIoControl(m_PICHandle, PIC_IO_ENABLE_VBUS, &vbus, sizeof(BOOL), NULL,0, NULL,NULL);
            Sleep(500);
        }
#endif        
        m_SyncAccess.Unlock();
         
        return TRUE;

    }


    USBOTG_MODE UsbOtgConfigure(USBOTG_MODE usbOtgMode)
    {
        return usbOtgMode;
    }
    
    BOOL    SessionRequest(BOOL fPulseLocConn, BOOL fPulseChrgVBus)
    {
        m_SyncAccess.Lock();
        EnterCriticalSection(&m_cs);
        CLK_OP(TRUE);

#if 0
        if (!m_ipmNotifiedD0Rdy)
        {
            if ( IPM_SetMinOp(m_IPMID,IPM_OP_104MHZ, 3000) != IPM_STATUS_SUCCESS)
                RETAILMSG(1, (_T("USBOTG: IPM_SetMinOp failed\r\n")));
            DWORD dwProcState = IPM_PROCESSOR_D0_RDY; 

                        // Notify IPM 
            if ( IPM_NotifyReadyForProcState(m_IPMID, dwProcState ,3000)==IPM_STATUS_SUCCESS)
            {
                DEBUGMSG(1, (_T("[IPM UsbOTG_ULPI] Notify IPM Ready For Processor state for driver Success!\r\n")));
            }
            else
            {
                RETAILMSG(1, (_T("[IPM UsbOTG_ULPI] Notify IPM Ready For Processor state for driver Fail!\r\n")));
            }
        }
#endif
        LeaveCriticalSection(&m_cs);

        Sleep(2);
        
        SwitchToSyncMode();

        
        m_pU2DReg->u2dotgicr = 0 ;   
         //enable VV, ID interrupt
        WriteULPIReg(ULPI_USB_INTR_EN_RISING_SET, ULPI_USB_INTR_VBUS_VALID | ULPI_USB_INTR_ID| ULPI_USB_INTR_SESS_VALID);    
        WriteULPIReg(ULPI_USB_INTR_EN_FALLING_SET, ULPI_USB_INTR_VBUS_VALID | ULPI_USB_INTR_ID| ULPI_USB_INTR_SESS_VALID);

        m_pU2DReg->u2dotgisr = m_pU2DReg->u2dotgicr;
        m_pU2DReg->u2dotgicr = XLLP_U2DOTGICR_ALLOTG ;   
        if (fPulseLocConn) 
        {
            RETAILMSG(1, (_T("Session Request Plus LocConn\r\n")));        
            WriteULPIReg(ULPI_FUNCTION, 0x5|ULPI_FUNCTION_SUSPENDM); //pull up D+
            Sleep(10);        
            WriteULPIReg(ULPI_FUNCTION, (0x1<<3)|ULPI_FUNCTION_SUSPENDM); //non driving

        }
        
        if (fPulseChrgVBus) 
        {
             /* start VBUS pulse SRP */
             WriteULPIReg(ULPI_OTG_CLR, ULPI_OTG_DISCHRGVBUS);
             WriteULPIReg(ULPI_OTG_SET, ULPI_OTG_CHRGVBUS);
             Sleep(80);
             /* stop VBUS pulse SRP */
             WriteULPIReg(ULPI_OTG_CLR, ULPI_OTG_CHRGVBUS);
             WriteULPIReg(ULPI_OTG_SET, ULPI_OTG_DISCHRGVBUS);
             m_UsbOtgInput.bit.b_bus_req =0;  //To avoid send SRP continually 
        }
        WriteULPIReg(ULPI_FUNCTION_CLR, ULPI_FUNCTION_SUSPENDM);

#if 0
        if ( IPM_ReleaseMinOp(m_IPMID, 3000) != IPM_STATUS_SUCCESS)
            RETAILMSG(1, (_T("USBOTG: IPM_ReleaseMinOp failed\r\n")));
            
        DWORD dwProcState = IPM_PROCESSOR_D0_RDY | IPM_PROCESSOR_RING_OSC_RDY | IPM_PROCESSOR_D2_RDY | IPM_PROCESSOR_D1_RDY; // Initial; // Initial

        // Notify IPM 
        if ( IPM_NotifyReadyForProcState(m_IPMID, dwProcState ,3000)==IPM_STATUS_SUCCESS)
        {
            DEBUGMSG(1, (_T("[IPM UsbOTG_ULPI] Notify IPM Ready For Processor state for driver Success!\r\n")));
        }
        else
        {
            RETAILMSG(1, (_T("[IPM UsbOTG_ULPI] Notify IPM Ready For Processor state for driver Fail!\r\n")));
        }
#endif       
        CLK_OP(FALSE);
        m_SyncAccess.Unlock();
        
        return TRUE;
    }

    BOOL DischargVBus()
    {
        WriteULPIReg(ULPI_OTG_SET,ULPI_OTG_DISCHRGVBUS);
        Sleep(10);
        return TRUE;
    }

    BOOL IsSE0()
    {
        BOOL ret;
        CLK_OP(TRUE);
        ret = ((m_pU2DReg->u2dotgusr&XLLP_U2DOTGUSR_LS0) ==0) && ((m_pU2DReg->u2dotgusr&XLLP_U2DOTGUSR_LS1) ==0);
        CLK_OP(FALSE);        
        return ret;

    }
    BOOL UpdateInput()
    {

        if (m_UsbOtgOutputValues.bit.loc_con || m_UsbOtgOutputValues.bit.loc_sof)
        {
            m_UsbOtgInput.bit.a_conn = m_UsbOtgInput.bit.b_conn = 1;
            DBG(1,(_T("UpdateInput a_conn is %d \r\n"),m_UsbOtgInput.bit.a_conn));
        }
        else
        {
            m_UsbOtgInput.bit.a_conn = m_UsbOtgInput.bit.b_conn = !IsSE0();
            DBG(1,(_T("UpdateInput b_conn is %d \r\n"),m_UsbOtgInput.bit.b_conn));

			if(m_UsbOtgState == USBOTG_a_wait_bcon)
			{
				for(int i = 0; i < 10; i++)
				{
					if (m_UsbOtgInput.bit.a_conn == 1)
						break;

					m_UsbOtgInput.bit.a_conn = m_UsbOtgInput.bit.b_conn = !IsSE0();
					Sleep(100);
				}
			}
        }

        return TRUE;
    }
    void SwitchToSyncMode_PowerUP()
    {
    
        unsigned long m_count=0;    

        unsigned long  U2DOTGCR=0;
        m_pU2DReg->u2dctrl &= ~XLLP_U2DCR_UDE;
        m_pU2DReg->u2dotgcr &= ~XLLP_U2DOTGCR_ULE;
        m_pU2DReg->u2dotgcr |= XLLP_U2DOTGCR_UTMID;

        m_pU2DReg->u2dotgcr |= XLLP_U2DOTGCR_RTSM ;
        U2DOTGCR = m_pU2DReg->u2dotgcr ;
        U2DOTGCR|= XLLP_U2DOTGCR_ULAF;
        U2DOTGCR &= ~XLLP_U2DOTGCR_SMAF;
        U2DOTGCR &= ~XLLP_U2DOTGCR_CKAF;
        m_pU2DReg->u2dotgcr = U2DOTGCR;
        m_pU2DReg->u2dotgcr |= XLLP_U2DOTGCR_ULE;
        DBG(1,(_T("++switch to sync mode \r\n")));
         
        if(m_pU2DReg->u2dotgusr & 0xF0000000)
        {
            m_count++;
            XllpOstDelayMilliSeconds((P_XLLP_OST_T)m_pOST, 2);
            if(m_count>5000)
            {
                RETAILMSG(1,(_T("*******ULPI reset!!! \r\n")));
                ULPI_Reset_PowerUP();
                return;

            }
        }
                
        WriteULPIReg(ULPI_INTERFACE_SET,ULPI_INTERFACE_PROTECT_DISABLE);
        
    }
    void ULPI_Reset_PowerUP()
    {
#if 0 
        if(GPX_SetDirection(XLLP_GPIO_ULPI_RESET, XLLP_GPIO_DIRECTION_OUT) != XLLP_STATUS_SUCCESS)
        {
            RETAILMSG(1, (_T("Set XLLP_GPIO_ULPI_RESET DIR Fail\r\n")));
        }
#endif       
        if(GPX_SetOutputLevel(XLLP_GPIO_ULPI_RESET, XLLP_LO) != XLLP_STATUS_SUCCESS)
        {
            RETAILMSG(1, (_T("Set XLLP_GPIO_ULPI_RESET LO FAIL\r\n")));
        }     
    
        XllpOstDelayMilliSeconds((P_XLLP_OST_T)m_pOST, 100);

        if(GPX_SetOutputLevel(XLLP_GPIO_ULPI_RESET, XLLP_HI) != XLLP_STATUS_SUCCESS)
        {
            RETAILMSG(1, (_T("Set XLLP_GPIO_ULPI_RESET HI FAIL\r\n")));
        }     
#if 0        
        if(GPX_SetDirection(XLLP_GPIO_ULPI_RESET, XLLP_GPIO_DIRECTION_IN) != XLLP_STATUS_SUCCESS)
        {
            RETAILMSG(1, (_T("Set XLLP_GPIO_ULPI_RESET DIR Fail\r\n")));
        }       
#endif
    }

    BOOL PowerUp() 
    {

        if(!USBOTG::PowerUp())
            return FALSE;
        CLK_OP(TRUE);
        ULPI_Reset_PowerUP();
        SwitchToSyncMode_PowerUP();
        
        m_pU2DReg->u2dotgicr = XLLP_U2DOTGICR_ALLOTG ;
        
        m_pU2DReg->u2dotgcr |= XLLP_U2DOTGCR_OTGEN;
        DWORD value;
        value = m_pU2DReg->u2dotgusr;
        DBG(1, (_T("OTG ULPI PowerUp is %x\r\n"),value));

		m_bResume = TRUE;

        SetEventData(m_hGPIOEvent, 1000);
        SetEvent(m_hGPIOEvent);

        return TRUE;
    }
    ///Power Down which called when system suspend.
    BOOL PowerDown()
    {

        DBG(1, (_T("otg ENABLE SIDECAR\n")));
    
        if(!USBOTG::PowerDown())
            return FALSE;
    
        SwitchToSyncMode_PowerUP();
        m_UsbOtgState = USBOTG_b_idle;

        return TRUE;
    }

    USBOTG_STATES  StateChange(USBOTG_STATES usbOtgState)
	{
		switch (usbOtgState)
		{
		case USBOTG_a_peripheral:
			if (m_UsbOtgInput.bit.b_bus_suspend == 1)
			{
				usbOtgState = USBOTG_a_wait_bcon;
				return usbOtgState;
			}
		}

		return USBOTG::StateChange(usbOtgState);
	}
	
    BOOL EventNotification()
	{
		m_UsbOtgInternal.bit.a_set_b_hnp_en = 1;

		//RETAILMSG(1, (_T("EventNotification\r\n")));
		return USBOTG::EventNotification();
	}
};
    ///Power Up which called when system resume. 
    DWORD OTGCable::ThreadRun()
    {
        return m_pOTGDevice->CableIST();
    }

    LPCTSTR ZyUSBOTG_ULPI::m_OtgStateString[]    = {
    TEXT("USBOTG_states_unknown"),
// A Port States
    TEXT("USBOTG_a_idle"),
    TEXT("USBOTG_a_wait_vrise"),
    TEXT("USBOTG_a_wait_bcon"),
    TEXT("USBOTG_a_host"),
    TEXT("USBOTG_a_suspend"),
    TEXT("USBOTG_a_peripheral"),
    TEXT("USBOTG_a_wait_vfall"),
    TEXT("USBOTG_a_vbus_err"),
// B Port States
    TEXT("USBOTG_b_idle"),
    TEXT("USBOTG_b_srp_init"),
    TEXT("USBOTG_b_peripheral"),
    TEXT("USBOTG_b_wait_acon"),
    TEXT("USBOTG_b_host")
    };



    USBOTG *    CreateUSBOTGObject(LPTSTR lpActivePath)
    {
        return new ZyUSBOTG_ULPI(lpActivePath);
    }

    void        DeleteUSBOTGObject(USBOTG * pUsbOtg )
    {
        delete pUsbOtg;
    }



